<?php
declare (strict_types=1);

namespace app\mall\model;

use app\mall\enum\OpUserEnum;
use app\mall\enum\OrderAdminOpsEnum;
use app\mall\enum\OrderRefundEnum;
use app\mall\enum\OrderStatusEnum;
use app\mall\model\traits\ClerkTrait;
use app\mall\model\traits\GoodsTrait;
use app\mall\model\traits\PayWayTrait;
use app\mall\model\traits\RegionTrait;
use app\mall\model\traits\StoreTrait;
use app\mall\model\traits\UserAddressTrait;
use app\mall\model\traits\UserTrait;
use think\Model;
use think\model\relation\HasMany;
use think\model\relation\HasOne;

/**
 * @mixin Model
 * @property OrderStatusEnum $status_enum
 * @property int goods_stock_id
 * @property MallGoodsStock goods_stock
 * @property MallOrderPay pay
 * @property MallLogisticsCompany logistics
 * @property string logistics_company_text
 * @property string sn
 * @property string logistics_sn
 * @property integer status
 * @property integer apply_refund
 * @property OrderRefundEnum apply_refund_enum
 * @property string status_text 订单状态中文
 * @property int logistics_company_id
 */
class MallOrder extends MallBase
{
    use GoodsTrait;
    use StoreTrait;
    use RegionTrait;
    use UserTrait;
    use ClerkTrait;
    use UserAddressTrait;
    use PayWayTrait;

    /**
     * 订单关联商品
     * @return HasMany
     */
    public function orderGoods(): HasMany
    {
        return $this->hasMany(MallOrderGoods::class, 'sn', 'sn');
    }

    /**
     * 订单日志
     * @return HasMany
     */
    public function logs(): HasMany
    {
        return $this->hasMany(MallOrderLog::class, 'sn', 'sn');
    }

    /**
     * @return array
     */
    public function getLogsListAttr()
    {
        $rs = [];
        if (!$this->logs) {
            return $rs;
        }
        $this->logs->append(['user']);
        return $this->logs->toArray();
    }

    /**
     * 订单关联
     * @return HasOne
     */
    public function pay(): HasOne
    {
        return $this->hasOne(MallOrderPay::class, 'sn', 'sn');
    }

    /**
     * 订单关联
     * @return HasOne
     */
    public function logistics(): HasOne
    {
        return $this->hasOne(MallLogisticsCompany::class, 'id', 'logistics_company_id');
    }

    public function getLogisticsCompanyTextAttr()
    {
        return $this->logistics ? $this->logistics['name'] : '';
    }

    public function getPayInfoAttr(): array
    {
        return $this->pay ? $this->pay->toArray() : [];
    }

    /**
     * 获取订单状态
     * @param $key
     * @param $data
     * @return string
     */
    public function getStatusTextAttr($key, $data): string
    {
        return $this->status_enum->getZhName();
    }

    public function getStatusEnumAttr($key, $data)
    {
        return new OrderStatusEnum($data['status']);
    }

    public function getGoodsStockAttr()
    {
        return MallGoodsStock::find($this->goods_stock_id);
    }

    public function getGoodsSpecAttr()
    {
        return $this->goods_stock ? $this->goods_stock->getData('spec') : null;
    }

    /**
     * 当前状态，管理员可操作项
     */
    public function getAdminOpsAttr()
    {
        $rs = $this->status_enum->getAdminOps();
        $rs = $this->filterSaleOps($rs);
        return $rs;
    }

    /**
     * 当前状态，店员可操作项
     */
    public function getClerkOpsAttr()
    {
        $rs = $this->status_enum->getClerkOps();
        $rs = $this->filterSaleOps($rs);
        return $rs;
    }

    protected function filterSaleOps($rs)
    {
        if ($this->status_enum->canRefund() && $this->apply_refund_enum->hasRefund()) {
            //如果有退款申请，则显示退款按钮
            foreach ([OrderAdminOpsEnum::REFUND, OrderAdminOpsEnum::REFUND_REFUSE] as $item) {
                $rs[] = [
                    'op' => $item,
                    'label' => (new OrderAdminOpsEnum($item))->getZhName()
                ];
            }
        }
        //已经评价过的不评价
        $index = $this->existOpKey(OrderAdminOpsEnum::EVALUATE, $rs);
        if ($rs && ($index !== false)) {
            if (!$this->canEvaluate([OpUserEnum::ADMIN, OpUserEnum::CLERK])) {
                unset($rs[$index]);
            }
        }
        return $rs;
    }

    protected function existOpKey($key, $rs)
    {
        foreach ($rs as $index => $r) {
            if ($r['op'] == $key) {
                return $index;
            }
        }
        return false;
    }

    /**
     * 当前状态用户可操作项
     */
    public function getUserOpsAttr()
    {
        $rs = $this->status_enum->getUserOps();
        if ($rs && $this->status_enum->canRefund() && !$this->apply_refund_enum->userCanRefund()) {
            //如果用户已申请过退款，并在处理中或者已退款，不显示退款按钮
            if (($index = $this->existOpKey(OrderAdminOpsEnum::REFUND, $rs)) !== false) {
                unset($rs[$index]);
            }
        }
        //已经评价过的不评价
        if ($rs && (($index = $this->existOpKey(OrderAdminOpsEnum::EVALUATE, $rs)) !== false)) {
            if ($this->canEvaluate(OpUserEnum::USER)) {
                unset($rs[$index]);
            }
        }
        return $rs;
    }

    public function appendDetailFields($fields = [])
    {
        $fieldsDefault = [
            'store_name', 'user_nickname', 'status_text',
            'goods_spec', 'goods_info', 'clerk_name', 'address_info',
            'pay_info', 'pay_way_text', 'logs_list', 'logistics_company_text'
        ];
        $this->append(array_merge($fieldsDefault, $fields));
    }

    public function getApplyRefundEnumAttr($key, $data): OrderRefundEnum
    {
        return new OrderRefundEnum($data['apply_refund']);
    }

    public function userCanRefund(): bool
    {
        return $this->apply_refund_enum->userCanRefund();
    }

    public function canEvaluate($userType): bool
    {
        if (!$this->status_enum->canEvaluate()) {
            return false;
        }
        $model = MallOrderEvaluate::where('sn', $this->sn);
        if (is_array($userType)) {
            $model->whereIn('user_type', $userType);
        } else {
            $model->where('user_type', $userType);
        }
        return $model->count() == 0;
    }
}
